package com.cms.dbUtils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.jfinal.kit.PathKit;
import com.mock.base.util.CollectionUtil;


@SuppressWarnings("static-access")
public class GenEntityMysql {
	
	private static final Logger logger = LoggerFactory.getLogger(GenEntityMysql.class);

	private static String packageOutPath = "com.ims.domain";// 指定实体生成所在包的路径
	private static String packageDaoOutPath = "com.ims.dao";// 指定实体Dao生成所在包的路径
	private static String authorName = "jianbinli";// 作者名字
	private static String[] colnames; // 列名数组
	private static String[] colTypes; // 列名类型数组
	private static String idtypeString;//用来记录主键的类型long或int
	private static int[] colSizes; // 列名大小数组
	private static boolean f_util = false; // 是否需要导入包java.util.*
	private static boolean f_sql = false; // 是否需要导入包java.sql.*
	private static boolean flag = true; 
	
		 
   
	public static void CreateTable(String tableName,PreparedStatement pStemt,Connection con) {
    	//用来重新配置util包是否需要导入
    	f_util = false;
    	String sql = "select * from " + tableName;
    	try {
			pStemt = con.prepareStatement(sql);
			ResultSetMetaData rsmd = pStemt.getMetaData();
			
			int size = rsmd.getColumnCount(); // 统计列
			colnames = new String[size];
			colTypes = new String[size];
			colSizes = new int[size];
			for (int i = 0; i < size; i++) {
				colnames[i] = rsmd.getColumnName(i + 1);
				colTypes[i] = rsmd.getColumnTypeName(i + 1);
		
				if (colTypes[i].equalsIgnoreCase("datetime")) {
					f_util = true;
				}
				if (colTypes[i].equalsIgnoreCase("image")
						|| colTypes[i].equalsIgnoreCase("text")) {
					f_sql = true;
				}
				colSizes[i] = rsmd.getColumnDisplaySize(i + 1);
			}
			String content = parse(colnames, colTypes, colSizes,tableName);
			writeFile( GenEntityMysql.class.newInstance().packageOutPath,"",tableName,content);
			parseDao(tableName);
    	} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}

    }
	/*
	 * 构造函数
	 */
	public GenEntityMysql(List<String> tableLists) {
		Properties prop = new Properties(); 
		 InputStream in = GenEntityMysql.class.getResourceAsStream("/jdbc.properties"); 
		 //文件在同一个包下   
			try {
				prop.load(in);
			} catch (IOException e2) {
				// TODO Auto-generated catch block
				e2.printStackTrace();
			} 
			String URL = prop.getProperty("url"); 
			String NAME = prop.getProperty("username");
			String PASS = prop.getProperty("password");
			String DRIVER = prop.getProperty("driverClassName"); 
			String core = prop.getProperty("core"); 
		// 创建连接
		Connection con = null;
		String tableList = "";
		//如果没有勾选任何表则将数据库中所有表都生成domian实体类
		if(CollectionUtil.isEmpty(tableLists)){
			
			tableList  = "select table_name from information_schema.tables where table_schema= "+"'"+core+"'";
			flag = true;
			
		}else{
			// 查要生成实体类的表
			//tableList = "select * from " + tablename;
			flag = false;
		}
		
		String tableName = "";
		PreparedStatement pStemt = null;
		try {
			try {
				Class.forName(DRIVER);
			} catch (ClassNotFoundException e) {
				logger.error(e.getMessage() + "can't find SQL DRIVER", e);
			}
			con = DriverManager.getConnection(URL, NAME, PASS);
			if(flag){
				String webRootPath = PathKit.getWebRootPath() + "/java";
				File dir = new File(webRootPath);
				deleteDir(dir);
				List<Map<String, Object>> executeQuery = DBUtil.executeQuery(con, tableList);
				//查询的list的结果集进行遍历分别进行创建domian实体
				if(CollectionUtil.isNotEmpty(executeQuery)){
					for (Map<String, Object> tableMap : executeQuery) {
						tableName = (String)tableMap.get("table_name");
						CreateTable(tableName, pStemt, con);
					}
				
					@SuppressWarnings("unused")
					String test = "D:\\test" +"/java";
					fileToZip(webRootPath,webRootPath,"code");
					return;
				}
			}else{
				String webRootPath = PathKit.getWebRootPath() + "/java";
				File dir = new File(webRootPath);
				deleteDir(dir);
				
				//前端传过来的tableLists进行遍历
				for (String tablename : tableLists) {
					CreateTable(tablename, pStemt, con);
					@SuppressWarnings("unused")
					String test = "D:\\test" +"/java";
				}
				fileToZip(webRootPath,webRootPath,"code");
			}
		} catch (SQLException e) {
			logger.error(e.getMessage() + "SQL have issue", e);
		} finally {
			//关闭连接
			 try {
				con.close();
			} catch (SQLException e) {
				logger.error(e.getMessage() + "close connet have issue", e);
			}
		}
	}

	/**
	 * 功能：生成实体类主体代码
	 * 
	 * @param colTypes
	 * @return
	 * @throws IllegalAccessException 
	 * @throws Exception 
	 */
	private static String parse(String[] colnames, String[] colTypes, int[] colSizes,String tableName) throws Exception {
		StringBuffer sb = new StringBuffer();
		sb.append("package " +  GenEntityMysql.class.newInstance().packageOutPath + ";\r\n");
		// 判断是否导入工具包
		if (f_util) {
			sb.append("import java.util.Date;\r\n");
		}
		if (f_sql) {
			sb.append("import java.sql.*;\r\n");
		}
		
		sb.append("\r\n");
		sb.append("import com.mock.simplemvc.annotation.Table;\r\n");
		// 注释部分
		sb.append("   /**\r\n");
		sb.append("    * " + tableName + " 实体类\r\n");
		sb.append("    * " + new Date() + " " +  GenEntityMysql.class.newInstance().authorName + "\r\n");
		sb.append("    */ \r\n");
		
		// 实体部分
		sb.append("@Table");
		sb.append("\r\npublic class " + StringToCap.initcap(tableName) + "{\r\n");
		processAllAttrs(sb);// 属性
		processAllMethod(sb);// get set方法
		sb.append("}\r\n");

		// System.out.println(sb.toString());
		return sb.toString();
	}
	/**
	 * 生成实体类对应的Dao代码
	* @Title: parseDao
	* @Description: TODO
	* @param @param colnames
	* @param @param colTypes
	* @param @param colSizes
	* @param @param tableName
	* @param @return
	* @param @throws Exception    
	* @return String   
	* @throws
	 */
	private static void parseDao(String tableName) throws Exception {
		
		StringBuffer sb = new StringBuffer();
		sb.append("package " +  GenEntityMysql.class.newInstance().packageDaoOutPath + ";\r\n");
		sb.append("import com.mock.simplemvc.annotation.Instance;\r\n");
		sb.append("import com.mock.simplemvc.dao.base.BaseDAO;\r\n");
		sb.append("import com.ims.domain." + StringToCap.initcap(tableName) +";");
		sb.append("\r\n");
		// 注释部分
		sb.append("   /**\r\n");
		sb.append("    * " + tableName + " 实体类\r\n");
		sb.append("    * " + new Date() + " " +  GenEntityMysql.class.newInstance().authorName + "\r\n");
		sb.append("    */ \r\n");
		
		// 实体部分
		sb.append("@Instance");
		sb.append("\r\npublic class " + StringToCap.initcap(tableName) +"Dao extends BaseDAO" +"{\r\n");
		sb.append(DaoBaseMethod.createBaseMethod(tableName, idtypeString));
		sb.append("}\r\n");
		sb.toString();
		writeFile( GenEntityMysql.class.newInstance().packageDaoOutPath ,"Dao", tableName,sb.toString());
	}
	
	private static void writeFile(String filePath,String affer,String tableName,String content) throws Exception{
		mkdir(PathKit.getWebRootPath()+"/java/");
		try {
			String webRootPath = PathKit.getWebRootPath();
			String outputPath = webRootPath + "/java/" +StringToCap.initcap(tableName) + affer + ".java";
			FileWriter fw = new FileWriter(outputPath);
			PrintWriter pw = new PrintWriter(fw);
			pw.println(content);
			pw.flush();
			pw.close();
			fw.close();
		} catch (IOException e) {
			logger.error(e.getMessage() + "write file failed", e);
		}
	}


	/**
	 * 功能：生成所有属性
	 * 
	 * @param sb
	 */
	private static void processAllAttrs(StringBuffer sb) {

		for (int i = 0; i < colnames.length; i++) {
			idtypeString = SqlType2JavaType.sqlType2JavaType(colTypes[0]);
			sb.append("\tprivate " + SqlType2JavaType.sqlType2JavaType(colTypes[i]) + " "
					+ StringToCap.initcapEent(colnames[i]) + ";\r\n");
		}

	}

	/**
	 * 功能：生成所有方法
	 * 
	 * @param sb
	 */
	private static void processAllMethod(StringBuffer sb) {

		for (int i = 0; i < colnames.length; i++) {
			sb.append("\tpublic void set" + StringToCap.initcap(colnames[i]) + "("
					+ SqlType2JavaType.sqlType2JavaType(colTypes[i]) + " " + StringToCap.initcapEent(colnames[i])
					+ "){\r\n");
			sb.append("\tthis." + StringToCap.initcapEent(colnames[i]) + "=" + StringToCap.initcapEent(colnames[i]) + ";\r\n");
			sb.append("\t}\r\n");
			sb.append("\tpublic " + SqlType2JavaType.sqlType2JavaType(colTypes[i]) + " get"
					+ StringToCap.initcap(colnames[i]) + "(){\r\n");
			sb.append("\t\treturn " + StringToCap.initcapEent(colnames[i]) + ";\r\n");
			sb.append("\t}\r\n");
		}

	}

	

	/**
	 * 无参构造函数
	 * 主要用来反射机制
	 */
	public GenEntityMysql() {
		super();
	}

	/**
	 * 出口 TODO
	 * 测试主函数
	 * @param args
	 * @throws Exception 
	 */
	public static void main(String[] args) {
		List<String> lists =new ArrayList<String>();
		new GenEntityMysql(lists);

	}
	
	public static boolean fileToZip(String sourceFilePath,String zipFilePath,String fileName){  
		        boolean flag = false;  
		        File sourceFile = new File(sourceFilePath);
		        FileInputStream fis = null;  
		        BufferedInputStream bis = null;  
		        FileOutputStream fos = null;  
		        ZipOutputStream zos = null;  
		          
		        if(sourceFile.exists() == false){  
		        	sourceFile.mkdir();
		            System.out.println("创建文件夹成功");  
		        }else{  
		            try {  
		                File zipFile = new File(zipFilePath + "/" + fileName +".zip");  
//		                if(zipFile.exists()){  
//		                    System.out.println(zipFilePath + "目录下存在名字为:" + fileName +".zip" +"打包文件.");  
//		                }else{  
		                    File[] sourceFiles = sourceFile.listFiles(); 

		                    if(null == sourceFiles || sourceFiles.length<1){  
		                        System.out.println("待压缩的文件目录：" + sourceFilePath + "里面不存在文件，无需压缩.");  
		                    }else{  
		                        fos = new FileOutputStream(zipFile);  
		                        zos = new ZipOutputStream(new BufferedOutputStream(fos));  
		                        byte[] bufs = new byte[1024*10];  
		                        for(int i=0;i<sourceFiles.length;i++){  
		                            //创建ZIP实体，并添加进压缩包  
		                            ZipEntry zipEntry = new ZipEntry(sourceFiles[i].getName());  
		                            zos.putNextEntry(zipEntry);  
		                            //读取待压缩的文件并写进压缩包里  
		                            fis = new FileInputStream(sourceFiles[i]);  
		                            bis = new BufferedInputStream(fis, 1024*10);  
		                            int read = 0;  
		                            while((read=bis.read(bufs, 0, 1024*10)) != -1){  
		                                zos.write(bufs,0,read);  
		                            }  
		                        } 
		                        zos.closeEntry();
		                        flag = true;  
		                    }  
		                   
//		                } 
		                    
		            } catch (FileNotFoundException e) {  
		                e.printStackTrace();  
		                throw new RuntimeException(e);  
		            } catch (IOException e) {  
		                e.printStackTrace();  
		                throw new RuntimeException(e);  
		            } finally{  
		                //关闭流  
		                try {  
		                	//及时关闭所有流防止出现不可预知错误
		                    if(null != bis) bis.close();  
		                    if(null != zos) zos.close(); 
		                    if(null != fos) fos.close();
		                    if(null != fis) fis.close();
		                } catch (IOException e) {  
		                    e.printStackTrace();  
		                    throw new RuntimeException(e);  
		                }  
		            }  
		        }  
		        return flag;  
		    }
	
			public static void mkdir(String sourceFilePath){
				File sourceFile = new File(sourceFilePath);
				sourceFile.mkdir();
	            System.out.println("创建文件夹成功======"+sourceFilePath); 
			}
			
			 
			 private static void deleteDir(File dir) {
			        if (dir.isDirectory()) {
			            String[] children = dir.list();
			            //递归删除目录中的子目录下
			            for (int i=0; i<children.length; i++) {
			                deleteDir(new File(dir, children[i]));
			            }
			        }
			        // 目录此时为空，可以删除
			         dir.delete();
			    }
			 

}